#include <iostream>
#include <unordered_map>
#include <memory>
#include <vector>

// 享元模式，主要用于减少创建对象的数量，以减少内存占用和提高性能的结构型设计模式
// 通过共享多个对象所共有的相同状态，使得在有限的内存容量中能够载入更多的对象
// 享元模式将对象的状态分为内部状态和外部状态
// 内部状态：是存储在享元对象内部的信息，它是不可变的，可以在多个享元对象之间共享
// 外部状态：是依赖于享元对象上下文的信息，它随着享元对象的每一次使用而变化，通常作为参数
// 传递给享元对象的方法。

// 享元模式的核心在于享元工厂类，负责创建和管理享元对象，并提供对外访问的接口。
// 当客户端请求一个享元对象时，享元工厂会首先检查是否已存在具有相同内部状态的享元对象，
// 如果存在则直接返回该对象，否则创建一个新的享元对象并存储起来。
// 通过这种方式，享元模式实现了对象的复用，减少了对象的创建和销毁次数。

// 模拟一个咖啡店订单系统，其中咖啡口味被视为享元对象，可以被多个订单共享
// 抽象享元接口
class CoffeeFlavor {
    public:
    virtual ~CoffeeFlavor() {}
    virtual void serve() const = 0;
};

// 具体享元类
class ConcreteCoffeeFlavor : public CoffeeFlavor {
    public:
    explicit ConcreteCoffeeFlavor(const std::string& flavorName):flavorName_(flavorName) {} 
    void serve() const override {
        std::cout << "Serving coffee flavor: " << flavorName_ << std::endl;
    }

    private:
    std::string flavorName_;
};

// 享元工厂
class CoffeeFlavorFactory {
    public:
    std::shared_ptr<CoffeeFlavor> getOrder(const std::string& flavor) {
        if(flavors_.find(flavor) == flavors_.end()) {
            flavors_[flavor] = std::make_shared<ConcreteCoffeeFlavor>(flavor);
        }
        return flavors_[flavor]; 
    }
    private:
    std::unordered_map<std::string,std::shared_ptr<CoffeeFlavor>> flavors_;
};


int main () {
    std::cout << "hello，享元模式" << std::endl;
    CoffeeFlavorFactory factory;

    // 创建几个不同的订单，但某些口味会被共享
    std::vector<std::string> orders = {"Espresso", "Latte", "Espresso", "Cappuccino", "Espresso"};
    for(const auto& order : orders) {
        auto flavor = factory.getOrder(order);
        flavor->serve();
    }

    return 0;
}